package xy.web;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import xy.web.startStop.StarStopLoader;
import xy.web.timer.TimerLoader;
import xy.web.timer.TimerRunner;

public final class MainServlet extends HttpServlet {

	private static final long serialVersionUID = -7962065549698615440L;

	protected void service(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		setEncoding(req, res);

		String actionId = getActionId(req);
		
		ActionItem actionItem = null;

		ActionContext context = null;

		int result = 0;
		
		try{
			if(actionId==null){
				throw NoFunctionException.INSTANCE;
			}

			log.info("Coming Action: "+actionId);
			
			context = ActionContextBuilder.build(req);

			actionItem = Actions.getActionItem(actionId);
			
			if(actionItem==null){
				throw NoFunctionException.INSTANCE;
			}
			
			context.action = actionItem;

			IAction action = (IAction)actionItem.getCls().newInstance();

			result = action.execute(context);
			
			if(context.isDownloadFile()){
				req.getRequestDispatcher("/frameJsp/downloadFile.jsp")
					.forward(req, res);
			}else{
				PageItem page =actionItem.getPageItem(result);
				String url = page.getUrl();
				if(page.isRedirect()){	//redirect, can not has /
					if(url.startsWith("/")){
						url = url.substring(1);
					}
					log.info("redirect: "+url);
					res.sendRedirect(url);
				}else{	//forward, need /
					if(!url.startsWith("/")){
						url = "/"+url;
					}
					log.info("forward: "+url);
					req.getRequestDispatcher(url).forward(req, res);
				}
			}

		}catch(Exception e){
			log.error("Error! "+actionId, e);
			
			req.setAttribute("error", e.getMessage());
			log.info("forward: /frameJsp/error.jsp");
			req.getRequestDispatcher("/frameJsp/error.jsp").forward(req, res);
			
		}finally{

		}
	}
	

	private String getActionId(HttpServletRequest req){
		// /ent/a.do
		String uri = req.getRequestURI();
		int p = uri.lastIndexOf("/");
		uri = uri.substring(p+1);
		p = uri.indexOf(".do");
		uri = uri.substring(0, p);
		return uri;
	}

	private void setEncoding(HttpServletRequest req,
			HttpServletResponse res) {
		try {
			ServletContext context = req.getSession().getServletContext();
			String defaultEncoding = context
					.getInitParameter("defaultEncoding");
			if (defaultEncoding == null || defaultEncoding.length() == 0) {
				defaultEncoding = System.getProperty("default.encoding");
			}
			if (defaultEncoding != null && defaultEncoding.length() > 0) {
				req.setCharacterEncoding(defaultEncoding);
				// response.setContentType("text/html; charset=GBK");
			}
		} catch (Exception exception) {
			log.error("setEncoding error", exception);
		}
	}
	
	public void init(ServletConfig config) throws ServletException {
		super.init(config);

		//application real path
		ServletContext application = getServletContext();
		String webRoot = application.getRealPath("/");
		
		if(webRoot.endsWith("/") || webRoot.endsWith("\\")){
			webRoot = webRoot.substring(0, webRoot.length()-1);
		}
		
		webRoot = webRoot.replace('\\', '/');
		String webInf = webRoot + "/WEB-INF";
		
		//save path
		SysConfig.webRoot = webRoot;
		SysConfig.webInf = webInf;
		
		try {

			loadAppConfig(config);

		} catch (Exception e1) {
			System.err.println("Can not load appConfig!");
			e1.printStackTrace();
			return;
		}
		SysConfig.downloadPath = SysConfig.getAppParam("downloadPath");
		SysConfig.uploadPath = SysConfig.getAppParam("uploadPath");
		
		//log4j
		System.setProperty("logPath", SysConfig.getAppParam("logPath"));
		PropertyConfigurator.configure(SysConfig.getAppParam("log4jProperties"));
		log = Logger.getLogger(this.getClass());
		log.info("Server starting now ................................ ");
		log.info(webRoot);
		log.info(webInf);
	
		try {
			StarStopLoader.load(SysConfig.getAppParam("start"));

			TimerLoader.load(SysConfig.getAppParam("timerAction"));
			TimerRunner.start();

		} catch (Exception e) {
			log.error("load faild", e);
			throw new ServletException(e);
		}
	}

	/**
	 * load sysConfig.xml
	 * 
	 * @param config
	 * @throws Exception
	 */
	private void loadAppConfig(ServletConfig config) throws Exception {
		String configFile = config.getInitParameter("appConfigXmlFile");
		if(configFile==null || configFile.trim().length()==0){
			throw new Exception("There is no appConfigXmlFile initParameter.");
		}
		
		File f = new File(configFile);
		if(!f.exists()){
			configFile = SysConfig.webRoot+configFile;
		}
		File file = new File(configFile);
		if(!file.exists()){
			throw new Exception("The appConfigXmlFile "
					+configFile+" is not exists!");
		}
		
		DocumentBuilderFactory factory = DocumentBuilderFactory
				.newInstance();
		factory.setValidating(false);
		Document doc = factory.newDocumentBuilder().parse(file);

		Element root = doc.getDocumentElement();
		
		NodeList param = root.getChildNodes();
		int size = param.getLength();
		SysConfig.param.clear();
		
		for(int i=0; i<size; i++){
			Node item = param.item(i);
			if(item.getNodeName().equals("param")){
				String paramName = item.getAttributes()
					.getNamedItem("name").getNodeValue().trim();
				String paramVal = item.getTextContent().trim();
				
				File p = new File(paramVal);
				if(!p.exists()){
					paramVal = SysConfig.webRoot + paramVal;
				}
				
				SysConfig.param.put(paramName, paramVal);

				System.out.println("SysConfig: "+paramName+"="+paramVal);
			}
		}

	}

	private Logger log;

	public void destroy() {
		log.info("...destroy...........");
		TimerRunner.stop();
		
		try {

			StarStopLoader.load(SysConfig.getAppParam("stop"));

		} catch (Exception e) {
			log.error("faild to process stoploader", e);
		}
		
		
		if(SysConfig.param!=null){
			SysConfig.param.clear();
		}
	}
}
